home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 April: Mac OS SDK / Dev.CD Apr 98 SDK1.toast / Development Kits (Disc 1) / Apple Game Sprockets / More Sprocket Examples 1.0 / GlyphaIV Sources / G4Graphics.c < prev    next >
Encoding:
Text File  |  1996-06-12  |  46.2 KB  |  1,506 lines  |  [TEXT/CWIE]

  1.  
  2. //============================================================================
  3. //----------------------------------------------------------------------------
  4. //                                    Graphics.c
  5. //----------------------------------------------------------------------------
  6. //============================================================================
  7.  
  8. // I like to isolate all the graphic routines - put them in their own file.
  9. // This way all the thousands of Rect variables and Pixmaps have a place to go.
  10. // Anyway, this file contains all the drawing routines.
  11.  
  12. #include "G4Externs.h"
  13. #include <Palettes.h>
  14. #include <QuickdrawText.h>
  15. #include <Fonts.h>
  16. #include <TextUtils.h>
  17. #include <Events.h>
  18.  
  19. #define kUpperEyeHeight            100
  20. #define kLowerEyeHeight            200
  21. #define kNumLightningPts        8
  22.  
  23.  
  24. void QuickUnionRect (Rect *, Rect *, Rect *);
  25. void CheckPlayerWrapAround (void);
  26. void DrawHand (void);
  27. void DrawEye (void);
  28. void DrawPlayer (void);
  29. void CheckEnemyWrapAround (short);
  30. void DrawEnemies (void);
  31. void DrawBanner (void);
  32. void DrawLava(void);
  33.  
  34. void HandleLava(void);
  35. void HandlePixelShatter(void);
  36.  
  37. Rect        backSrcRect, workSrcRect, obSrcRect, playerSrcRect;
  38. Rect        numberSrcRect, idleSrcRect, enemyWalkSrcRect, enemyFlySrcRect;
  39. Rect        obeliskRects[4], playerRects[11], numbersSrc[11], numbersDest[11];
  40. Rect        flameSrcRect, flameDestRects[2], flameRects[4], eggSrcRect;
  41. Rect        platformSrcRect, platformCopyRects[9], helpSrcRect, eyeSrcRect, bannerSrcRect;
  42. Rect        helpSrc, helpDest, handSrcRect, handRects[2], eyeRects[4];
  43. Point        leftLightningPts[kNumLightningPts], rightLightningPts[kNumLightningPts];
  44. CGrafPtr    origBackSrcMap, backSrcMap, workSrcMap, obeliskSrcMap, playerSrcMap, eyeSrcMap;
  45. CGrafPtr    numberSrcMap, idleSrcMap, enemyWalkSrcMap, enemyFlySrcMap;
  46. CGrafPtr    flameSrcMap, eggSrcMap, bannerSrcMap, platformSrcMap, helpSrcMap, handSrcMap;
  47. GrafPtr        playerMaskMap, enemyWalkMaskMap, enemyFlyMaskMap, eggMaskMap;
  48. GrafPtr        handMaskMap, eyeMaskMap, obeliskMaskMap;
  49. Boolean        whichList, helpOpen, scoresOpen;
  50.  
  51. short numPixelShatter;
  52. pixelShatter thePixelShatter[kMaxPixelShatter];
  53.  
  54. extern    handInfo    theHand;
  55. extern    eyeInfo        theEye;
  56. extern    prefsInfo    thePrefs;
  57. extern    playerType    thePlayer;
  58. extern    enemyType    theEnemies[];
  59. extern    Rect        enemyRects[24];
  60. extern    long        theScore, wasTensOfThousands;
  61. extern    short        livesLeft, levelOn, numEnemies;
  62. extern    Boolean        evenFrame;
  63.  
  64. extern short lightningCount;
  65. void HandleLightning();
  66.  
  67.  
  68. extern short oldFrameRate;
  69.  
  70. // in DR3 of DrawSprocket the underlay buffer will give the game the
  71. // ability to not worry about keeping track fo the update rects.  As it
  72. // is right now, if you use update rects you have to save the update
  73. // rectangle for each frame, and the number of frames will vary depending
  74. // on the state of triple buffering and page flipping.
  75. // 
  76. // Once the Underlay buffers are operational, enabiling this #define
  77. // will allow DS to optimize the screen updates instead of doing
  78. // a full screen copy (as happens in Glypha)
  79. //#define USE_INVALID_RECTS 1
  80.  
  81. //==============================================================  Functions
  82. //--------------------------------------------------------------  DrawPlatforms
  83.  
  84. // This function draws all the platforms on the background pixmap and the…
  85. // work pixmap.  It needs to know merely how many of them to draw.
  86.  
  87. void DrawPlatforms (short howMany)
  88. {
  89.     if (howMany > 3)            // If there are more than 3 platforms…
  90.     {                            // Draw a platform to background pixmap.
  91.         CopyBits(&((GrafPtr)platformSrcMap)->portBits, 
  92.                 &((GrafPtr)backSrcMap)->portBits, 
  93.                 &platformCopyRects[2], &platformCopyRects[7], srcCopy, 0L);
  94.         
  95.                                 // Draw a platform to work pixmap.
  96.         CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  97.                 &((GrafPtr)workSrcMap)->portBits, 
  98.                 &platformCopyRects[7], &platformCopyRects[7], srcCopy, 0L);
  99.         #ifdef USE_INVALID_RECTS
  100.         DSpContext_InvalBackBufferRect( gTheContext, &platformCopyRects[7] );
  101.         #endif
  102.  
  103.                                 // Add rectangle to update list to be drawn to screen.
  104.                                 // Ditto for a second platform.
  105.         CopyBits(&((GrafPtr)platformSrcMap)->portBits, 
  106.                 &((GrafPtr)backSrcMap)->portBits, 
  107.                 &platformCopyRects[4], &platformCopyRects[8], srcCopy, 0L);
  108.         CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  109.                 &((GrafPtr)workSrcMap)->portBits, 
  110.                 &platformCopyRects[8], &platformCopyRects[8], srcCopy, 0L);
  111.         #ifdef USE_INVALID_RECTS
  112.         DSpContext_InvalBackBufferRect( gTheContext, &platformCopyRects[8] );
  113.         #endif
  114.  
  115.     }
  116.     else                        // If there are 3 or less platforms…
  117.     {
  118.         CopyBits(&((GrafPtr)platformSrcMap)->portBits, 
  119.                 &((GrafPtr)backSrcMap)->portBits, 
  120.                 &platformCopyRects[3], &platformCopyRects[7], srcCopy, 0L);
  121.         CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  122.                 &((GrafPtr)workSrcMap)->portBits, 
  123.                 &platformCopyRects[7], &platformCopyRects[7], srcCopy, 0L);
  124.         #ifdef USE_INVALID_RECTS
  125.         DSpContext_InvalBackBufferRect( gTheContext, &platformCopyRects[7] );
  126.         #endif
  127.  
  128.         
  129.         CopyBits(&((GrafPtr)platformSrcMap)->portBits, 
  130.                 &((GrafPtr)backSrcMap)->portBits, 
  131.                 &platformCopyRects[5], &platformCopyRects[8], srcCopy, 0L);
  132.         CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  133.                 &((GrafPtr)workSrcMap)->portBits, 
  134.                 &platformCopyRects[8], &platformCopyRects[8], srcCopy, 0L);
  135.         #ifdef USE_INVALID_RECTS
  136.         DSpContext_InvalBackBufferRect( gTheContext, &platformCopyRects[8] );
  137.         #endif
  138.  
  139.     }
  140.     
  141.     if (howMany > 5)        // If there are more than 5 platforms…
  142.     {
  143.         CopyBits(&((GrafPtr)platformSrcMap)->portBits, 
  144.                 &((GrafPtr)backSrcMap)->portBits, 
  145.                 &platformCopyRects[0], &platformCopyRects[6], srcCopy, 0L);
  146.         CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  147.                 &((GrafPtr)workSrcMap)->portBits, 
  148.                 &platformCopyRects[6], &platformCopyRects[6], srcCopy, 0L);
  149.         #ifdef USE_INVALID_RECTS
  150.         DSpContext_InvalBackBufferRect( gTheContext, &platformCopyRects[6] );
  151.         #endif
  152.  
  153.     }
  154.     else                    // If there are 5 or less platforms…
  155.     {
  156.         CopyBits(&((GrafPtr)platformSrcMap)->portBits, 
  157.                 &((GrafPtr)backSrcMap)->portBits, 
  158.                 &platformCopyRects[1], &platformCopyRects[6], srcCopy, 0L);
  159.         CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  160.                 &((GrafPtr)workSrcMap)->portBits, 
  161.                 &platformCopyRects[6], &platformCopyRects[6], srcCopy, 0L);
  162.         #ifdef USE_INVALID_RECTS
  163.         DSpContext_InvalBackBufferRect( gTheContext, &platformCopyRects[6] );
  164.         #endif
  165.  
  166.     }
  167. }
  168.  
  169. //--------------------------------------------------------------  ScrollHelp
  170.  
  171. // This function scrolls the help screen.  You pass it a number of pixels…
  172. // to scroll up or down (positive or negative number).
  173.  
  174. void ScrollHelp (short scrollDown)
  175. {
  176.     // don't do any drawing, drawing is done by the idle animation automatically
  177.     
  178.     OffsetRect(&helpSrc, 0, scrollDown);        // Move the source rectangle.
  179.     
  180.     if (helpSrc.bottom > 398)                    // Check to see we don't go too far.
  181.     {
  182.         helpSrc.bottom = 398;
  183.         helpSrc.top = helpSrc.bottom - 199;
  184.     }
  185.     else if (helpSrc.top < 0)
  186.     {
  187.         helpSrc.top = 0;
  188.         helpSrc.bottom = helpSrc.top + 199;
  189.     }
  190. }
  191.  
  192. //--------------------------------------------------------------  OpenHelp
  193.  
  194. // Bring up the help screen.  This is a kind of "wipe" or "barn door" effect.
  195.  
  196. void OpenHelp (void)
  197. {
  198.     Rect        wallSrc, wallDest;
  199.     short        i;
  200.     
  201.     SetRect(&helpSrc, 0, 0, 231, 0);    // Initialize source and destination rects.
  202.     helpDest = helpSrc;
  203.     OffsetRect(&helpDest, 204, 171);
  204.     
  205.     SetRect(&wallSrc, 0, 0, 231, 199);
  206.     OffsetRect(&wallSrc, 204, 171);
  207.     wallDest = wallSrc;
  208.     
  209.     for (i = 0; i < 199; i ++)            // Loop through 1 pixel at a time.
  210.     {
  211.         DSpContext_GetBackBuffer( gTheContext, kDSpBufferKind_Normal, &workSrcMap );
  212.  
  213.         DumpBackToWorkMap();                    // clear the screen
  214.         HandleLava();
  215.         HandlePixelShatter();
  216.         DrawTorches();
  217.         DrawBanner();
  218.         DrawLava();
  219.         DrawPixelShatter();
  220.  
  221.         LogNextTick(1L);                // Speed governor.
  222.         helpSrc.bottom++;                // Grow help source rect.
  223.         helpDest.bottom++;                // Grow help dest as well.
  224.         wallSrc.bottom--;                // Shrink wall source.
  225.         wallDest.top++;                    // Shrink wall dest.
  226.         
  227.                                         // So, as the help graphic grows, the wall graphic…
  228.                                         // shrinks.  Thus it is as though the wall is…
  229.                                         // lifting up to expose the help screen beneath.
  230.         
  231.         CopyBits(    &((GrafPtr)helpSrcMap)->portBits, 
  232.                     &((GrafPtr)workSrcMap)->portBits, 
  233.                     &helpSrc, &helpDest, srcCopy, 0L);
  234.         #ifdef USE_INVALID_RECTS
  235.         DSpContext_InvalBackBufferRect( gTheContext, &helpDest );
  236.         #endif
  237.  
  238.  
  239.         CopyBits(    &((GrafPtr)backSrcMap)->portBits, 
  240.                     &((GrafPtr)workSrcMap)->portBits, 
  241.                     &wallSrc, &wallDest, srcCopy, 0L);
  242.         #ifdef USE_INVALID_RECTS
  243.         DSpContext_InvalBackBufferRect( gTheContext, &wallDest );
  244.         #endif
  245.  
  246.                                         // Copy slightly larger help screen.
  247.  
  248.         DSpContext_SwapBuffers( gTheContext, NULL, NULL );
  249.     }
  250.     helpOpen = TRUE;                    // When done, set flag to indicate help is open.
  251. }
  252.  
  253. //--------------------------------------------------------------  CloseWall
  254.  
  255. // Close the wall over whatever screen is up (help screen or high scores).
  256. // Since the wall just comes down over the opening - covering whatever was beneath,…
  257. // it's simpler than the above function.
  258.  
  259. void CloseWall (void)
  260. {
  261.     DSpContext_GetBackBuffer( gTheContext, kDSpBufferKind_Normal, &workSrcMap );
  262.     DumpBackToWorkMap();                    // clear the screen
  263.     DSpContext_SwapBuffers( gTheContext, NULL, NULL );
  264. }
  265.  
  266. //--------------------------------------------------------------  OpenHighScores
  267.  
  268. // This function is practically identical to the OpenHelp().  The only real…
  269. // difference is that we must first draw all the high scores offscreen before…
  270. // lifting the wall to reveal them.
  271.  
  272. void OpenHighScores (void)
  273. {
  274.     RGBColor    theRGBColor, wasColor;
  275.     Rect        wallSrc, wallDest;
  276.     Rect        scoreSrc, scoreDest;
  277.     Str255        scoreStr;
  278.     short        i, scoreWide;
  279.     
  280.     SetRect(&scoreSrc, 0, 0, 231, 0);                // Initialize source and dest rects.
  281.     OffsetRect(&scoreSrc, 204, 171);
  282.     scoreDest = scoreSrc;
  283.     
  284.     SetRect(&wallSrc, 0, 0, 231, 199);
  285.     OffsetRect(&wallSrc, 204, 171);
  286.     wallDest = wallSrc;
  287.     
  288.     SetPort((GrafPtr)workSrcMap);                    // We'll draw scores to the work pixmap.
  289.     PaintRect(&wallSrc);                            // Paint it black.
  290.     
  291.     GetForeColor(&wasColor);                        // Save the foreground color.
  292.     
  293.     TextFont(geneva);                                // Use Geneva 12 point Bold font.
  294.     TextSize(12);
  295.     TextFace(bold);
  296.     
  297.     Index2Color(132, &theRGBColor);                    // Get the 132nd color in RGB form.
  298.     RGBForeColor(&theRGBColor);                        // Make this color the pen color.
  299.     MoveTo(scoreSrc.left + 36, scoreSrc.top + 20);    // Get pen in right position to draw.
  300.     DrawString("\pGlypha IV High Scores");            // Draw the title.
  301.     
  302.     TextFont(geneva);                                // Use Geneva 9 point Bold font.
  303.     TextSize(9);
  304.     TextFace(bold);
  305.     
  306.     for (i = 0; i < 10; i++)                        // Walk through all 10 high scores.
  307.     {
  308.         Index2Color(133, &theRGBColor);                // Use color 133 (in palette).
  309.         RGBForeColor(&theRGBColor);
  310.         NumToString((long)i + 1L, scoreStr);        // Draw "place" (1, 2, 3, …).
  311.         MoveTo(scoreSrc.left + 8, scoreSrc.top + 40 + (i * 16));
  312.         DrawString(scoreStr);
  313.         
  314.         Index2Color(128, &theRGBColor);                // Use color 128 (from palette).
  315.         RGBForeColor(&theRGBColor);
  316.         MoveTo(scoreSrc.left + 32, scoreSrc.top + 40 + (i * 16));
  317.         DrawString(thePrefs.highNames[i]);            // Draw the high score name (Sue, …).
  318.         
  319.         Index2Color(164, &theRGBColor);                // Use color 164 (from palette).
  320.         RGBForeColor(&theRGBColor);
  321.         NumToString(thePrefs.highScores[i], scoreStr);
  322.         scoreWide = StringWidth(scoreStr);            // Right justify.
  323.         MoveTo(scoreSrc.left + 191 - scoreWide, scoreSrc.top + 40 + (i * 16));
  324.         DrawString(scoreStr);                        // Draw the high score (12,000, …).
  325.         
  326.         Index2Color(134, &theRGBColor);                // Use color 134 (from palette).
  327.         RGBForeColor(&theRGBColor);
  328.         NumToString(thePrefs.highLevel[i], scoreStr);
  329.         scoreWide = StringWidth(scoreStr);            // Right justify.
  330.         MoveTo(scoreSrc.left + 223 - scoreWide, scoreSrc.top + 40 + (i * 16));
  331.         DrawString(scoreStr);                        // Draw highest level (12, 10, …).
  332.     }
  333.     
  334.     RGBForeColor(&wasColor);                        // Restore foreground color.
  335.  
  336.     for (i = 0; i < 199; i ++)                        // Now the standard scroll functions.
  337.     {
  338.         WaitForNextTick();
  339.         
  340.         DSpContext_GetBackBuffer( gTheContext, kDSpBufferKind_Normal, &workSrcMap );
  341.         DumpBackToWorkMap();                    // clear the screen
  342.     
  343.         LogNextTick(1L);                // Speed governor.
  344.         scoreSrc.bottom++;
  345.         scoreDest.bottom++;
  346.         wallSrc.bottom--;
  347.         wallDest.top++;
  348.         
  349.                                         // So, as the help graphic grows, the wall graphic…
  350.                                         // shrinks.  Thus it is as though the wall is…
  351.                                         // lifting up to expose the help screen beneath.
  352.         
  353.         CopyBits(    &((GrafPtr)workSrcMap)->portBits, 
  354.                     &((GrafPtr)workSrcMap)->portBits, 
  355.                     &scoreSrc, &scoreDest, srcCopy, 0L);
  356.         #ifdef USE_INVALID_RECTS
  357.         DSpContext_InvalBackBufferRect( gTheContext, &scoreDest );
  358.         #endif
  359.  
  360.  
  361.         CopyBits(    &((GrafPtr)backSrcMap)->portBits, 
  362.                     &((GrafPtr)workSrcMap)->portBits, 
  363.                     &wallSrc, &wallDest, srcCopy, 0L);
  364.         #ifdef USE_INVALID_RECTS
  365.         DSpContext_InvalBackBufferRect( gTheContext, &wallDest );
  366.         #endif
  367.  
  368.                                         // Copy slightly larger help screen.
  369.  
  370.         DSpContext_SwapBuffers( gTheContext, NULL, NULL );
  371.     }
  372.     
  373.     scoresOpen = TRUE;                                // Flag that the scores are up.
  374. }
  375.  
  376. //--------------------------------------------------------------  UpdateLivesNumbers
  377.  
  378. // During a game, this function is called to reflect the current number of lives.
  379. // This is "lives remaining", so 1 is subtracted before displaying it to the screen.
  380. // The lives is "wrapped around" after 99.  So 112 lives will display as 12.  It's…
  381. // a lot easier to handle numbers this way (it beats a recursive function that might…
  382. // potentially draw across the entire screen.
  383.  
  384. void UpdateLivesNumbers (void)
  385. {
  386.     short        digit;
  387.     
  388.     digit = (livesLeft - 1) / 10;        // Get the "10's" digit.
  389.     digit = digit % 10L;                // Keep it less than 10 (0 -> 9).
  390.     if ((digit == 0) && ((livesLeft - 1) < 10))
  391.         digit = 10;                        // Use a "blank" space if zero and less than 10.
  392.                                         // Draw digit.
  393.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  394.             &((GrafPtr)backSrcMap)->portBits, 
  395.             &numbersSrc[digit], &numbersDest[0], srcCopy, 0L);
  396.     #ifdef USE_INVALID_RECTS
  397.     DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[0] );
  398.     #endif
  399.  
  400.  
  401.     digit = (livesLeft - 1) % 10;        // Get 1's digit.
  402.                                         // Draw digit.
  403.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  404.             &((GrafPtr)backSrcMap)->portBits, 
  405.             &numbersSrc[digit], &numbersDest[1], srcCopy, 0L);
  406.     #ifdef USE_INVALID_RECTS
  407.     DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[1] );
  408.     #endif
  409.  
  410. }
  411.  
  412. //--------------------------------------------------------------  UpdateScoreNumbers
  413.  
  414. // This function works just like the above function.  However, we allow the…
  415. // score to go to 6 digits (999,999) before rolling over.  Note however, that…
  416. // in both the case of the score, number of lives, etc., the game does in fact…
  417. // keep track of the "actual" number.  It is just that only so many digits are…
  418. // being displayed.
  419.  
  420. void UpdateScoreNumbers (void)
  421. {
  422.     long        digit;
  423.  
  424.     digit = theScore / 100000L;        // Get "hundreds of thousands" digit
  425.     digit = digit % 10L;            // Clip off anything greater than 9.
  426.     if ((digit == 0) && (theScore < 1000000L))
  427.         digit = 10;                    // Use blank space if zero.
  428.                                     // Draw digit.
  429.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  430.             &((GrafPtr)backSrcMap)->portBits, 
  431.             &numbersSrc[digit], &numbersDest[2], srcCopy, 0L);
  432.     #ifdef USE_INVALID_RECTS
  433.     DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[2] );
  434.     #endif
  435.  
  436.  
  437.     digit = theScore / 10000L;        // Get "tens of thousands" digit.
  438.     if (digit > wasTensOfThousands)    // Check for "extra life" here.
  439.     {
  440.         livesLeft++;                // Increment number of lives.
  441.         UpdateLivesNumbers();        // Reflect new lives on screen.
  442.         wasTensOfThousands = digit;    // Note that life was given.
  443.     }
  444.     digit = digit % 10L;            // Clip off anything greater than 9.
  445.     if ((digit == 0) && (theScore < 100000L))
  446.         digit = 10;                    // Use blank space if zero.
  447.                                     // Draw digit.
  448.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  449.             &((GrafPtr)backSrcMap)->portBits, 
  450.             &numbersSrc[digit], &numbersDest[3], srcCopy, 0L);
  451.     #ifdef USE_INVALID_RECTS
  452.     DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[3] );
  453.     #endif
  454.  
  455.     
  456.     digit = theScore / 1000L;        // Handle "thousands" digit.
  457.     digit = digit % 10L;
  458.     if ((digit == 0) && (theScore < 10000L))
  459.         digit = 10;
  460.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  461.             &((GrafPtr)backSrcMap)->portBits, 
  462.             &numbersSrc[digit], &numbersDest[4], srcCopy, 0L);
  463.     #ifdef USE_INVALID_RECTS
  464.     DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[4] );
  465.     #endif
  466.  
  467.  
  468.     digit = theScore / 100L;        // Handle 100's digit.
  469.     digit = digit % 10L;
  470.     if ((digit == 0) && (theScore < 1000L))
  471.         digit = 10;
  472.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  473.             &((GrafPtr)backSrcMap)->portBits, 
  474.             &numbersSrc[digit], &numbersDest[5], srcCopy, 0L);
  475.     #ifdef USE_INVALID_RECTS
  476.     DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[5] );
  477.     #endif
  478.  
  479.  
  480.     digit = theScore / 10L;            // Handle 10's digit.
  481.     digit = digit % 10L;
  482.     if ((digit == 0) && (theScore < 100L))
  483.         digit = 10;
  484.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  485.             &((GrafPtr)backSrcMap)->portBits, 
  486.             &numbersSrc[digit], &numbersDest[6], srcCopy, 0L);
  487.     #ifdef USE_INVALID_RECTS
  488.     DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[6] );
  489.     #endif
  490.  
  491.     
  492.     digit = theScore % 10L;            // Handle 1's digit.
  493.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  494.             &((GrafPtr)backSrcMap)->portBits, 
  495.             &numbersSrc[digit], &numbersDest[7], srcCopy, 0L);
  496.     #ifdef USE_INVALID_RECTS
  497.     DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[7] );
  498.     #endif
  499. }
  500.  
  501. //--------------------------------------------------------------  UpdateLevelNumbers
  502.  
  503. // Blah, blah, blah.  Just like the above functions but handles displaying the…
  504. // level the player is on.  We allow 3 digits here (up to 999) before wrapping.
  505.  
  506. void UpdateLevelNumbers (void)
  507. {
  508.     short        digit;
  509.     short        workNumber;
  510.     
  511. //    workNumber = levelOn;
  512.     workNumber = oldFrameRate;
  513.         
  514.     digit = (workNumber + 1) / 100;        // Do 100's digit.
  515.     digit = digit % 10L;
  516.     if ((digit == 0) && ((workNumber + 1) < 1000))
  517.         digit = 10;
  518.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  519.             &((GrafPtr)backSrcMap)->portBits, 
  520.             &numbersSrc[digit], &numbersDest[8], srcCopy, 0L);
  521.     #ifdef USE_INVALID_RECTS
  522.     DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[3] );
  523.     #endif
  524.     
  525.     digit = (workNumber + 1) / 10;            // Do 10's digit.
  526.     digit = digit % 10L;
  527.     if ((digit == 0) && ((workNumber + 1) < 100))
  528.         digit = 10;
  529.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  530.             &((GrafPtr)backSrcMap)->portBits, 
  531.             &numbersSrc[digit], &numbersDest[9], srcCopy, 0L);
  532.     #ifdef USE_INVALID_RECTS
  533.     DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[9] );
  534.     #endif
  535.     
  536.     digit = (workNumber + 1) % 10;            // Do 1's digit.
  537.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  538.             &((GrafPtr)backSrcMap)->portBits, 
  539.             &numbersSrc[digit], &numbersDest[10], srcCopy, 0L);
  540.     #ifdef USE_INVALID_RECTS
  541.     DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[10] );
  542.     #endif
  543. }
  544.  
  545. //--------------------------------------------------------------  GenerateLightning
  546.  
  547. // This function takes a point (h and v) and then generates two lightning bolts…
  548. // (one from the tip of each obelisk) to the point.  It does this by generating…
  549. // a list of segments (as the lightning is broken up into segements).  The drawing…
  550. // counterpart to this function will draw a line connecting these segements (a sort…
  551. // of dot-to-dot).
  552.  
  553. void GenerateLightning (short h, short v)
  554. {
  555.     #define kLeftObeliskH        172
  556.     #define kLeftObeliskV        250
  557.     #define kRightObeliskH        468
  558.     #define kRightObeliskV        250
  559.     #define kWander                16
  560.     
  561.     short        i, leftDeltaH, rightDeltaH, leftDeltaV, rightDeltaV, range;
  562.     
  563.     leftDeltaH = h - kLeftObeliskH;                // Determine the h and v distances between…
  564.     rightDeltaH = h - kRightObeliskH;            // obelisks and the target point.
  565.     leftDeltaV = v - kLeftObeliskV;
  566.     rightDeltaV = v - kRightObeliskV;
  567.     
  568.     for (i = 0; i < kNumLightningPts; i++)        // Calculate an even spread of points between…
  569.     {                                            // obelisk tips and the target point.
  570.         leftLightningPts[i].h = (leftDeltaH * i) / (kNumLightningPts - 1) + kLeftObeliskH;
  571.         leftLightningPts[i].v = (leftDeltaV * i) / (kNumLightningPts - 1) + kLeftObeliskV;
  572.         rightLightningPts[i].h = (rightDeltaH * i) / (kNumLightningPts - 1) + kRightObeliskH;
  573.         rightLightningPts[i].v = (rightDeltaV * i) / (kNumLightningPts - 1) + kRightObeliskV;
  574.     }
  575.     
  576.     range = kWander * 2 + 1;                    // Randomly scatter the points vertically…
  577.     for (i = 1; i < kNumLightningPts - 1; i++)    // but NOT the 1st or last points.
  578.     {
  579.         leftLightningPts[i].v += RandomInt(range) - kWander;
  580.         rightLightningPts[i].v += RandomInt(range) - kWander;
  581.     }
  582. }
  583.  
  584. void DrawObelisks (void)
  585. {    
  586.     if ((lightningCount > 0) && evenFrame)        // Draw them "inverted"
  587.     {
  588.         CopyMask(    &((GrafPtr)obeliskSrcMap)->portBits,        // src
  589.                     &((GrafPtr)obeliskMaskMap)->portBits,        // mask
  590.                     &((GrafPtr) workSrcMap)->portBits,             // dst
  591.                     &obeliskRects[0],                             // src rect
  592.                     &obeliskRects[0],                             // mask rect
  593.                     &obeliskRects[2]);                            // dst rect
  594.         #ifdef USE_INVALID_RECTS
  595.         DSpContext_InvalBackBufferRect( gTheContext, &obeliskRects[2] );
  596.         #endif
  597.  
  598.         CopyMask(    &((GrafPtr)obeliskSrcMap)->portBits,        // src
  599.                     &((GrafPtr)obeliskMaskMap)->portBits,        // mask
  600.                     &((GrafPtr) workSrcMap)->portBits,             // dst
  601.                     &obeliskRects[1],                             // src rect
  602.                     &obeliskRects[1],                             // mask rect
  603.                     &obeliskRects[3]);                            // dst rect
  604.         #ifdef USE_INVALID_RECTS
  605.         DSpContext_InvalBackBufferRect( gTheContext, &obeliskRects[3] );
  606.         #endif
  607.     }
  608.     else
  609.     {
  610.         CopyMask(    &((GrafPtr)backSrcMap)->portBits,        // src
  611.                     &((GrafPtr)obeliskMaskMap)->portBits,        // mask
  612.                     &((GrafPtr) workSrcMap)->portBits,             // dst
  613.                     &obeliskRects[2],                             // src rect
  614.                     &obeliskRects[0],                             // mask rect
  615.                     &obeliskRects[2]);                             // dst rect
  616.         #ifdef USE_INVALID_RECTS
  617.         DSpContext_InvalBackBufferRect( gTheContext, &obeliskRects[2] );
  618.         #endif
  619.  
  620.         CopyMask(    &((GrafPtr)backSrcMap)->portBits,        // src
  621.                     &((GrafPtr)obeliskMaskMap)->portBits,        // mask
  622.                     &((GrafPtr) workSrcMap)->portBits,             // dst
  623.                     &obeliskRects[3],                             // src rect
  624.                     &obeliskRects[1],                             // mask rect
  625.                     &obeliskRects[3]);                            // dst rect
  626.         #ifdef USE_INVALID_RECTS
  627.         DSpContext_InvalBackBufferRect( gTheContext, &obeliskRects[3] );
  628.         #endif
  629.     }
  630. }
  631.  
  632.  
  633. void StrikeLightningWork (void)
  634. {
  635.     short        i;
  636.     GrafPtr        oldPort;
  637.     RGBColor     yellow = {65535, 65535, 0};
  638.     Rect        theRect;
  639.     
  640.     GetPort(&oldPort);
  641.     SetPort((GrafPtr)workSrcMap);
  642.     PenSize(1, 2);                                // Use a tall pen.
  643.     RGBForeColor(&yellow);
  644.                                                 // Draw lightning bolts with inverted pen.
  645.     MoveTo(leftLightningPts[0].h, leftLightningPts[0].v);
  646.     for (i = 0; i < kNumLightningPts - 1; i++)    // Draw left lightning bolt.
  647.     {
  648.         MoveTo(leftLightningPts[i].h, leftLightningPts[i].v);
  649.         LineTo(leftLightningPts[i + 1].h - 1, leftLightningPts[i + 1].v);
  650.     }
  651.     SetRect( &theRect, leftLightningPts[0].h, leftLightningPts[0].v, 
  652.         leftLightningPts[kNumLightningPts].h - 1, leftLightningPts[kNumLightningPts].v );
  653.     #ifdef USE_INVALID_RECTS
  654.     DSpContext_InvalBackBufferRect( gTheContext, &theRect );
  655.     #endif
  656.     
  657.     MoveTo(rightLightningPts[0].h, rightLightningPts[0].v);
  658.     for (i = 0; i < kNumLightningPts - 1; i++)    // Draw right lightning bolt.
  659.     {
  660.         MoveTo(rightLightningPts[i].h, rightLightningPts[i].v);
  661.         LineTo(rightLightningPts[i + 1].h - 1, rightLightningPts[i + 1].v);
  662.     }
  663.     SetRect( &theRect, rightLightningPts[0].h, rightLightningPts[0].v, 
  664.         rightLightningPts[kNumLightningPts].h - 1, rightLightningPts[kNumLightningPts].v );
  665.     #ifdef USE_INVALID_RECTS
  666.     DSpContext_InvalBackBufferRect( gTheContext, &theRect );
  667.     #endif
  668.     
  669.     PenNormal();                                // Return pen to normal.
  670.     
  671.     SetPort(oldPort);
  672. }
  673.  
  674. //--------------------------------------------------------------  DumpBackToWorkMap
  675.  
  676. // Simple handy function that copies the entire background pixmap to the…
  677. // work pixmap.
  678. //--
  679.  
  680. //--------------------------------------------------------------  DumpBackToWorkMap
  681.  
  682. // Simple handy function that copies the entire background pixmap to the…
  683. // work pixmap.
  684.  
  685.  
  686. static inline void ClassicDumpBackToWork(void)
  687. {
  688.     // this is doing a full clean of the work map from the source map, don't inval
  689.     // this rect.
  690.     //
  691.     // • this will go away once DrawSprocket Underlays are used (in DR3 release)
  692.     CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  693.             &((GrafPtr)workSrcMap)->portBits, 
  694.             &backSrcRect, &backSrcRect, srcCopy, 0L);
  695. }
  696.  
  697. // faster on some machines, on others it is slow because of dcbz
  698. static inline void FastDumpBackToWorkMap (void)
  699. {
  700.     CGrafPtr srcGrafPtr = backSrcMap;
  701.     PixMap *srcMap = *(srcGrafPtr->portPixMap);
  702.     char *src = srcMap->baseAddr;
  703.     UInt32 srcBump = srcMap->rowBytes & 0x3fff;
  704.     
  705.     CGrafPtr dstGrafPtr = workSrcMap;
  706.     PixMap *dstMap = *(dstGrafPtr->portPixMap);
  707.     char *dst = dstMap->baseAddr;
  708.     UInt32 dstBump = dstMap->rowBytes & 0x3fff;
  709.     
  710.     int count;
  711.     
  712.     for(count = 0; count < 480; count++)
  713.     {
  714.         BlockMoveData(src,dst,640);
  715.         
  716.         src += srcBump;
  717.         dst += dstBump;
  718.     }
  719. }
  720.  
  721. void DumpBackToWorkMap(void)
  722. {    
  723.     ClassicDumpBackToWork();
  724. }
  725.  
  726. //--------------------------------------------------------------  QuickUnionRect
  727.  
  728. // The Mac Toolbox gives you a UnionRect() function, but, like any Toolbox…
  729. // routine, if we can do it faster, we ought to.  Well, the function below…
  730. // is quick because (among other reasons), it assumes that the two rects…
  731. // being compared are the same size.
  732. //
  733. // Notes from Cary Farrier: Sorry John I don't agree with that advice.  You
  734. // may be able to do something faster, but the speed gain you achieve may not
  735. // be worth the effort required to develop, test, and debug the code.  John's
  736. // advice is good for some scenarios, but it is the exception and not the
  737. // rule.
  738. void QuickUnionRect (Rect *rect1, Rect *rect2, Rect *whole)
  739. {
  740.     if (rect1->left < rect2->left)        // See if we're to use rect1's left.
  741.     {
  742.         whole->left = rect1->left;
  743.         whole->right = rect2->right;
  744.     }
  745.     else                                // Use rect2's left.
  746.     {
  747.         whole->left = rect2->left;
  748.         whole->right = rect1->right;
  749.     }
  750.     
  751.     if (rect1->top < rect2->top)        // See if we're to use rect1's top.
  752.     {
  753.         whole->top = rect1->top;
  754.         whole->bottom = rect2->bottom;
  755.     }
  756.     else                                // Use rect2's top.
  757.     {
  758.         whole->top = rect2->top;
  759.         whole->bottom = rect1->bottom;
  760.     }
  761. }
  762.  
  763. //--------------------------------------------------------------  CheckPlayerWrapAround
  764.  
  765. // This handles drawing wrap-around.  It is such that, when a player walks partly…
  766. // off the right edge of the screen, you see the player peeking through on the left…
  767. // side of the screen.  Since we can't (shouldn't) assume that the physical screen…
  768. // memory wraps around, we'll draw the right player clipped against the right edge…
  769. // of the screen and draw a SECOND PLAYER on the left edge (clipped to the left).
  770.  
  771. void CheckPlayerWrapAround (void)
  772. {
  773.     Rect        wrapRect, wasWrapRect, src;
  774.     
  775.     if (thePlayer.dest.right > 640)        // Player off right edge of screen.
  776.     {
  777.         thePlayer.wrapping = TRUE;        // Set "wrapping" flag.
  778.         wrapRect = thePlayer.dest;        // Start out with copy of player bounds.
  779.         wrapRect.left -= 640;            // Offset it a screenwidth to left.
  780.         wrapRect.right -= 640;
  781.                                         // Ditto with old location.
  782.         wasWrapRect = thePlayer.wasDest;
  783.         wasWrapRect.left -= 640;
  784.         wasWrapRect.right -= 640;
  785.         
  786.         if (thePlayer.mode == kBones)    // Draw second bones.
  787.         {
  788.             src = playerRects[thePlayer.srcNum];
  789.             src.bottom = src.top + thePlayer.frame;
  790.             CopyMask(&((GrafPtr)playerSrcMap)->portBits, 
  791.                     &((GrafPtr)playerMaskMap)->portBits, 
  792.                     &((GrafPtr)workSrcMap)->portBits, 
  793.                     &src, &src, &wrapRect);
  794.             #ifdef USE_INVALID_RECTS
  795.             DSpContext_InvalBackBufferRect( gTheContext, &wrapRect );
  796.             #endif
  797.         }
  798.         else                            // Draw second player (not bones).
  799.         {
  800.             CopyMask(&((GrafPtr)playerSrcMap)->portBits, 
  801.                     &((GrafPtr)playerMaskMap)->portBits, 
  802.                     &((GrafPtr)workSrcMap)->portBits, 
  803.                     &playerRects[thePlayer.srcNum], 
  804.                     &playerRects[thePlayer.srcNum], 
  805.                     &wrapRect);
  806.             #ifdef USE_INVALID_RECTS
  807.             DSpContext_InvalBackBufferRect( gTheContext, &wrapRect );
  808.             #endif
  809.         }
  810.         thePlayer.wrap = wrapRect;
  811.     }
  812.     else if (thePlayer.dest.left < 0)    // Else if off the left edge…
  813.     {
  814.         thePlayer.wrapping = TRUE;        // Set "wrapping" flag.
  815.         wrapRect = thePlayer.dest;        // Start out with copy of player bounds.
  816.         wrapRect.left += 640;            // Offset it a screenwidth to right.
  817.         wrapRect.right += 640;
  818.                                         // Ditto with old location.
  819.         wasWrapRect = thePlayer.wasDest;
  820.         wasWrapRect.left += 640;
  821.         wasWrapRect.right += 640;
  822.         
  823.         if (thePlayer.mode == kBones)    // Draw second bones.
  824.         {
  825.             src = playerRects[thePlayer.srcNum];
  826.             src.bottom = src.top + thePlayer.frame;
  827.             CopyMask(&((GrafPtr)playerSrcMap)->portBits, 
  828.                     &((GrafPtr)playerMaskMap)->portBits, 
  829.                     &((GrafPtr)workSrcMap)->portBits, 
  830.                     &src, &src, &wrapRect);
  831.             #ifdef USE_INVALID_RECTS
  832.             DSpContext_InvalBackBufferRect( gTheContext, &wrapRect );
  833.             #endif
  834.         }
  835.         else                            // Draw second player (not bones).
  836.         {
  837.             CopyMask(&((GrafPtr)playerSrcMap)->portBits, 
  838.                     &((GrafPtr)playerMaskMap)->portBits, 
  839.                     &((GrafPtr)workSrcMap)->portBits, 
  840.                     &playerRects[thePlayer.srcNum], 
  841.                     &playerRects[thePlayer.srcNum], 
  842.                     &wrapRect);
  843.             #ifdef USE_INVALID_RECTS
  844.             DSpContext_InvalBackBufferRect( gTheContext, &wrapRect );
  845.             #endif
  846.         }
  847.         thePlayer.wrap = wrapRect;
  848.     }
  849.     else
  850.         thePlayer.wrapping = FALSE;        // Otherwise, we're not wrapping.
  851. }
  852.  
  853. //--------------------------------------------------------------  DrawTorches
  854.  
  855. // This handles drawing the two torch's flames.  It chooses randomly from…
  856. // 4 torch graphics and draws right over the old torches.
  857.  
  858. void DrawTorches (void)
  859. {
  860.     short        who;
  861.     
  862.     who = RandomInt(4);
  863.     if (evenFrame)        // Only draw 1 torch - left on even frames…
  864.     {
  865.         CopyBits(&((GrafPtr)flameSrcMap)->portBits, 
  866.                 &((GrafPtr)workSrcMap)->portBits, 
  867.                 &flameRects[who], &flameDestRects[0], srcCopy, 0L);
  868.         #ifdef USE_INVALID_RECTS
  869.         DSpContext_InvalBackBufferRect( gTheContext, &flameDestRects[0] );
  870.         #endif
  871.     }
  872.     else                // and draw the right torch on odd frames.
  873.     {                    // We do this even/odd thing for speed.  Why draw both?
  874.         CopyBits(&((GrafPtr)flameSrcMap)->portBits, 
  875.                 &((GrafPtr)workSrcMap)->portBits, 
  876.                 &flameRects[who], &flameDestRects[1], srcCopy, 0L);
  877.         #ifdef USE_INVALID_RECTS
  878.         DSpContext_InvalBackBufferRect( gTheContext, &flameDestRects[1] );
  879.         #endif
  880.     }
  881. }
  882.  
  883. //--------------------------------------------------------------  DrawHand
  884.  
  885. // This function takes care of drawing the hand offscreen.  There are only…
  886. // two (well really three) choices - hand open, hand clutching (or no hand…
  887. // in which case both options are skipped).
  888.  
  889. void DrawHand (void)
  890. {
  891.     theHand.dest.right = theHand.dest.left + 56;
  892.     theHand.dest.bottom = theHand.dest.top + 57;
  893.  
  894.     if (theHand.mode == kOutGrabeth)        // Fingers open.
  895.     {
  896.         CopyMask(&((GrafPtr)handSrcMap)->portBits, 
  897.                 &((GrafPtr)handMaskMap)->portBits, 
  898.                 &((GrafPtr)workSrcMap)->portBits, 
  899.                 &handRects[0], 
  900.                 &handRects[0], 
  901.                 &theHand.dest);
  902.         #ifdef USE_INVALID_RECTS
  903.         DSpContext_InvalBackBufferRect( gTheContext, &theHand.dest );
  904.         #endif
  905.     }
  906.     else if (theHand.mode == kClutching)    // Fingers clenched.
  907.     {
  908.         CopyMask(&((GrafPtr)handSrcMap)->portBits, 
  909.                 &((GrafPtr)handMaskMap)->portBits, 
  910.                 &((GrafPtr)workSrcMap)->portBits, 
  911.                 &handRects[1], 
  912.                 &handRects[1], 
  913.                 &theHand.dest);
  914.         #ifdef USE_INVALID_RECTS
  915.         DSpContext_InvalBackBufferRect( gTheContext, &theHand.dest );
  916.         #endif
  917.     }
  918. }
  919.  
  920. //--------------------------------------------------------------  DrawEye
  921.  
  922. // This function draws the eye (if it's floating about - stalking).
  923.  
  924. void DrawEye (void)
  925. {
  926.     if (theEye.mode == kStalking)
  927.     {
  928.         CopyMask(&((GrafPtr)eyeSrcMap)->portBits, 
  929.                 &((GrafPtr)eyeMaskMap)->portBits, 
  930.                 &((GrafPtr)workSrcMap)->portBits, 
  931.                 &eyeRects[theEye.srcNum], 
  932.                 &eyeRects[theEye.srcNum], 
  933.                 &theEye.dest);
  934.         #ifdef USE_INVALID_RECTS
  935.         DSpContext_InvalBackBufferRect( gTheContext, &theEye.dest );
  936.         #endif
  937.     }
  938. }
  939.  
  940. //--------------------------------------------------------------  DrawPlayer
  941.  
  942. // Although called "DrawPlayer()", this function actually does its drawing…
  943. // offscreen.  It is the above routine that will finally copy our offscreen…
  944. // work to the main screen.  Anyway, the below function draws the player…
  945. // offscreen in the correct position and state.
  946.  
  947. void DrawPlayer (void)
  948. {
  949.     Rect        src;
  950.     
  951.     if ((evenFrame) && (thePlayer.mode == kIdle))
  952.     {            // On even frames, we'll draw the "flashed" graphic of the player.
  953.                 // If you've played Glypha, you notice that the player begins a…
  954.                 // game flashing alternately between bones and a normal player.
  955.         CopyMask(&((GrafPtr)idleSrcMap)->portBits, 
  956.                 &((GrafPtr)playerMaskMap)->portBits, 
  957.                 &((GrafPtr)workSrcMap)->portBits, 
  958.                 &idleSrcRect, 
  959.                 &playerRects[thePlayer.srcNum], 
  960.                 &thePlayer.dest);
  961.         #ifdef USE_INVALID_RECTS
  962.         DSpContext_InvalBackBufferRect( gTheContext, &thePlayer.dest );
  963.         #endif
  964.     }
  965.     else if (thePlayer.mode == kBones)
  966.     {            // If the player is dead and a pile of bones…
  967.         src = playerRects[thePlayer.srcNum];
  968.         src.bottom = src.top + thePlayer.frame;
  969.         CopyMask(&((GrafPtr)playerSrcMap)->portBits, 
  970.                 &((GrafPtr)playerMaskMap)->portBits, 
  971.                 &((GrafPtr)workSrcMap)->portBits, 
  972.                 &src, &src, &thePlayer.dest);
  973.         #ifdef USE_INVALID_RECTS
  974.         DSpContext_InvalBackBufferRect( gTheContext, &thePlayer.dest );
  975.         #endif
  976.     }
  977.     else        // Else, if the player is neither idle nor dead…
  978.     {
  979.         CopyMask(&((GrafPtr)playerSrcMap)->portBits, 
  980.                 &((GrafPtr)playerMaskMap)->portBits, 
  981.                 &((GrafPtr)workSrcMap)->portBits, 
  982.                 &playerRects[thePlayer.srcNum], 
  983.                 &playerRects[thePlayer.srcNum], 
  984.                 &thePlayer.dest);
  985.         #ifdef USE_INVALID_RECTS
  986.         DSpContext_InvalBackBufferRect( gTheContext, &thePlayer.dest );
  987.         #endif
  988.     }
  989.                 // Now we add the player to the update rect list.
  990.                 // Record old locations.
  991.     thePlayer.wasH = thePlayer.h;
  992.     thePlayer.wasV = thePlayer.v;
  993.                 // Record old bounds rect.
  994.     thePlayer.wasDest = thePlayer.dest;
  995. }
  996.  
  997. //--------------------------------------------------------------  CheckEnemyWrapAround
  998.  
  999. // This function both determines whether or not an enemy (sphinx) is wrapping around.
  1000. // If it is, the "second" wrapped-around enemy is drawn.
  1001.  
  1002. void CheckEnemyWrapAround (short who)
  1003. {
  1004.     Rect        wrapRect, wasWrapRect, src;
  1005.     
  1006.     if (theEnemies[who].dest.right > 640)    // Is enemy off the right edge of screen?
  1007.     {
  1008.         wrapRect = theEnemies[who].dest;    // Copy bounds.
  1009.         wrapRect.left -= 640;                // Offset bounds copy to left (one screen width).
  1010.         wrapRect.right -= 640;
  1011.                                             // Ditto with old bounds.
  1012.         wasWrapRect = theEnemies[who].wasDest;
  1013.         wasWrapRect.left -= 640;
  1014.         wasWrapRect.right -= 640;
  1015.                                             // Handle "egg" enemies.
  1016.         if ((theEnemies[who].mode == kFalling) || (theEnemies[who].mode == kEggTimer))
  1017.         {                                    // Handle "egg" enemy sinking into platform.
  1018.             if ((theEnemies[who].mode == kEggTimer) && (theEnemies[who].frame < 24))
  1019.             {
  1020.                 src = eggSrcRect;
  1021.                 src.bottom = src.top + theEnemies[who].frame;
  1022.             }
  1023.             else
  1024.                 src = eggSrcRect;
  1025.             CopyMask(&((GrafPtr)eggSrcMap)->portBits, 
  1026.                     &((GrafPtr)eggMaskMap)->portBits, 
  1027.                     &((GrafPtr)workSrcMap)->portBits, 
  1028.                     &src, &src, &wrapRect);
  1029.             #ifdef USE_INVALID_RECTS
  1030.             DSpContext_InvalBackBufferRect( gTheContext, &wrapRect );
  1031.             #endif
  1032.         }
  1033.         else                                // Otherwise, if enemy not an egg…
  1034.         {
  1035.             CopyMask(&((GrafPtr)enemyFlySrcMap)->portBits, 
  1036.                     &((GrafPtr)enemyFlyMaskMap)->portBits, 
  1037.                     &((GrafPtr)workSrcMap)->portBits, 
  1038.                     &enemyRects[theEnemies[who].srcNum], 
  1039.                     &enemyRects[theEnemies[who].srcNum], 
  1040.                     &wrapRect);
  1041.             #ifdef USE_INVALID_RECTS
  1042.             DSpContext_InvalBackBufferRect( gTheContext, &wrapRect );
  1043.             #endif
  1044.         }
  1045.     }
  1046.     else if (theEnemies[who].dest.left < 0)    // Check to see if enemy off left edge instead.
  1047.     {
  1048.         wrapRect = theEnemies[who].dest;    // Make a copy of enemy bounds.
  1049.         wrapRect.left += 640;                // Offset it right one screens width.
  1050.         wrapRect.right += 640;
  1051.                                             // Ditto with old bounds.
  1052.         wasWrapRect = theEnemies[who].wasDest;
  1053.         wasWrapRect.left += 640;
  1054.         wasWrapRect.right += 640;
  1055.         if ((theEnemies[who].mode == kFalling) || (theEnemies[who].mode == kEggTimer))
  1056.         {                                    // Blah, blah, blah.  This is just like the above.
  1057.             if ((theEnemies[who].mode == kEggTimer) && (theEnemies[who].frame < 24))
  1058.             {
  1059.                 src = eggSrcRect;
  1060.                 src.bottom = src.top + theEnemies[who].frame;
  1061.             }
  1062.             else
  1063.                 src = eggSrcRect;
  1064.             CopyMask(&((GrafPtr)eggSrcMap)->portBits, 
  1065.                     &((GrafPtr)eggMaskMap)->portBits, 
  1066.                     &((GrafPtr)workSrcMap)->portBits, 
  1067.                     &src, &src, &wrapRect);
  1068.             #ifdef USE_INVALID_RECTS
  1069.             DSpContext_InvalBackBufferRect( gTheContext, &wrapRect );
  1070.             #endif
  1071.         }
  1072.         else
  1073.         {
  1074.             CopyMask(&((GrafPtr)enemyFlySrcMap)->portBits, 
  1075.                     &((GrafPtr)enemyFlyMaskMap)->portBits, 
  1076.                     &((GrafPtr)workSrcMap)->portBits, 
  1077.                     &enemyRects[theEnemies[who].srcNum], 
  1078.                     &enemyRects[theEnemies[who].srcNum], 
  1079.                     &wrapRect);
  1080.             #ifdef USE_INVALID_RECTS
  1081.             DSpContext_InvalBackBufferRect( gTheContext, &wrapRect );
  1082.             #endif
  1083.         }
  1084.     }
  1085. }
  1086.  
  1087. //--------------------------------------------------------------  DrawEnemies
  1088.  
  1089. // This function draws all the sphinx enemies (or eggs if they're in that state).
  1090. // It doesn't handle wrap-around (the above function does) but it does call it.
  1091.  
  1092. void DrawEnemies (void)
  1093. {
  1094.     Rect        src;
  1095.     short        i;
  1096.     
  1097.     for (i = 0; i < numEnemies; i++)    // Go through all enemies.
  1098.     {
  1099.         switch (theEnemies[i].mode)        // Handle the different modes as seperate cases.
  1100.         {
  1101.             case kSpawning:                // Spawning enemies are "growing" out of the platform.
  1102.             src = enemyRects[theEnemies[i].srcNum];
  1103.             src.bottom = src.top + theEnemies[i].frame;
  1104.             CopyMask(&((GrafPtr)enemyWalkSrcMap)->portBits, 
  1105.                     &((GrafPtr)enemyWalkMaskMap)->portBits, 
  1106.                     &((GrafPtr)workSrcMap)->portBits, 
  1107.                     &src, &src, &theEnemies[i].dest);
  1108.             #ifdef USE_INVALID_RECTS
  1109.             DSpContext_InvalBackBufferRect( gTheContext, &theEnemies[i].dest );
  1110.             #endif
  1111.                     
  1112.                                         // Don't need to check wrap-around, when enemies…
  1113.                                         // spawn, they're never on the edge of screen.
  1114.             theEnemies[i].wasDest = theEnemies[i].dest;
  1115.             theEnemies[i].wasH = theEnemies[i].h;
  1116.             theEnemies[i].wasV = theEnemies[i].v;
  1117.             break;
  1118.             
  1119.             case kFlying:                // Flying enemies are air borne (gee).
  1120.             CopyMask(&((GrafPtr)enemyFlySrcMap)->portBits, 
  1121.                     &((GrafPtr)enemyFlyMaskMap)->portBits, 
  1122.                     &((GrafPtr)workSrcMap)->portBits, 
  1123.                     &enemyRects[theEnemies[i].srcNum], &enemyRects[theEnemies[i].srcNum], 
  1124.                     &theEnemies[i].dest);
  1125.             #ifdef USE_INVALID_RECTS
  1126.             DSpContext_InvalBackBufferRect( gTheContext, &theEnemies[i].dest );
  1127.             #endif
  1128.                     
  1129.             CheckEnemyWrapAround(i);    // I like the word "air bourne".
  1130.             theEnemies[i].wasDest = theEnemies[i].dest;
  1131.             theEnemies[i].wasH = theEnemies[i].h;
  1132.             theEnemies[i].wasV = theEnemies[i].v;
  1133.             break;
  1134.             
  1135.             case kWalking:                // Walking enemies are walking.  Enemies.
  1136.             CopyMask(&((GrafPtr)enemyWalkSrcMap)->portBits, 
  1137.                     &((GrafPtr)enemyWalkMaskMap)->portBits, 
  1138.                     &((GrafPtr)workSrcMap)->portBits, 
  1139.                     &enemyRects[theEnemies[i].srcNum], &enemyRects[theEnemies[i].srcNum], 
  1140.                     &theEnemies[i].dest);
  1141.             #ifdef USE_INVALID_RECTS
  1142.             DSpContext_InvalBackBufferRect( gTheContext, &theEnemies[i].dest );
  1143.             #endif
  1144.                                         // Don't need to check wrap-around, enemies walk…
  1145.                                         // only briefly, and never off edge of screen.
  1146.             theEnemies[i].wasDest = theEnemies[i].dest;
  1147.             theEnemies[i].wasH = theEnemies[i].h;
  1148.             theEnemies[i].wasV = theEnemies[i].v;
  1149.             break;
  1150.             
  1151.             case kFalling:                // Falling enemies are in fact eggs!
  1152.             CopyMask(&((GrafPtr)eggSrcMap)->portBits, 
  1153.                     &((GrafPtr)eggMaskMap)->portBits, 
  1154.                     &((GrafPtr)workSrcMap)->portBits, 
  1155.                     &eggSrcRect, &eggSrcRect, &theEnemies[i].dest);
  1156.             #ifdef USE_INVALID_RECTS
  1157.             DSpContext_InvalBackBufferRect( gTheContext, &theEnemies[i].dest );
  1158.             #endif
  1159.                     
  1160.             CheckEnemyWrapAround(i);    // Check for wrap around.
  1161.             theEnemies[i].wasDest = theEnemies[i].dest;
  1162.             theEnemies[i].wasH = theEnemies[i].h;
  1163.             theEnemies[i].wasV = theEnemies[i].v;
  1164.             break;
  1165.             
  1166.             case kEggTimer:                // These are idle, perhaps hatching, eggs.
  1167.             if (theEnemies[i].frame < 24)
  1168.             {                            // Below countdown = 24, the egss are sinking…
  1169.                 src = eggSrcRect;        // into the platform (hatch time!).
  1170.                 src.bottom = src.top + theEnemies[i].frame;
  1171.             }
  1172.             else
  1173.                 src = eggSrcRect;
  1174.             CopyMask(&((GrafPtr)eggSrcMap)->portBits, 
  1175.                     &((GrafPtr)eggMaskMap)->portBits, 
  1176.                     &((GrafPtr)workSrcMap)->portBits, 
  1177.                     &src, &src, &theEnemies[i].dest);
  1178.             #ifdef USE_INVALID_RECTS
  1179.             DSpContext_InvalBackBufferRect( gTheContext, &theEnemies[i].dest );
  1180.             #endif
  1181.                     
  1182.             CheckEnemyWrapAround(i);    // Check for wrap around.
  1183.             theEnemies[i].wasDest = theEnemies[i].dest;
  1184.             theEnemies[i].wasH = theEnemies[i].h;
  1185.             theEnemies[i].wasV = theEnemies[i].v;
  1186.             break;
  1187.         }
  1188.     }
  1189. }
  1190.  
  1191. //------------- DrawBanner
  1192. void DrawBanner (void)
  1193. {
  1194.     Rect destRect;
  1195.     Rect srcRect;
  1196.     long start = (TickCount() / 2) % 1280;
  1197.     long seg1Len;
  1198.     long seg2Len;
  1199.     
  1200.     if (start <= 640) 
  1201.     {
  1202.         seg1Len = 640;
  1203.         seg2Len = 0;
  1204.     }
  1205.     else
  1206.     {
  1207.         seg1Len = 1280 - start;
  1208.         seg2Len = 640 - seg1Len;
  1209.     }
  1210.     
  1211.     SetRect(&destRect,
  1212.             0,        // left
  1213.             460,    // top
  1214.             seg1Len,    // right
  1215.             480);    // bottom
  1216.     
  1217.             
  1218.     SetRect(&srcRect,
  1219.             start,
  1220.             0,
  1221.             start + seg1Len,
  1222.             20);
  1223.             
  1224.             
  1225.     CopyBits(    &((GrafPtr)bannerSrcMap)->portBits, 
  1226.                 &((GrafPtr)workSrcMap)->portBits, 
  1227.                 &srcRect, &destRect, srcCopy, 0L);
  1228.     #ifdef USE_INVALID_RECTS
  1229.     DSpContext_InvalBackBufferRect( gTheContext, &destRect );
  1230.     #endif
  1231.                 
  1232.     if (seg2Len > 0)
  1233.     {
  1234.         destRect.left = seg1Len;
  1235.         destRect.right = 640;
  1236.         srcRect.left = 0;
  1237.         srcRect.right = seg2Len;
  1238.         
  1239.         CopyBits(    &((GrafPtr)bannerSrcMap)->portBits, 
  1240.                     &((GrafPtr)workSrcMap)->portBits, 
  1241.                     &srcRect, &destRect, srcCopy, 0L);
  1242.     #ifdef USE_INVALID_RECTS
  1243.     DSpContext_InvalBackBufferRect( gTheContext, &destRect );
  1244.     #endif
  1245.     }
  1246.  
  1247. }
  1248.  
  1249. //--------------------------------------------------------------  DrawPixelShatter
  1250.  
  1251. void DrawPixelShatter (void)
  1252. {
  1253.     int i;
  1254.     CGrafPtr theGrafPtr = workSrcMap;
  1255.     PixMap *theMap = *(theGrafPtr->portPixMap);
  1256.     short h,v;
  1257.     short rowBytes = theMap->rowBytes & 0x3fff;
  1258.     short minH = 1000, minV = 1000, maxH = 0, maxV = 0;
  1259.     Rect theRect;
  1260.     
  1261.     for(i = 0; i < numPixelShatter; i++)
  1262.     {
  1263.         char *addr = theMap->baseAddr;
  1264.         int offset = 0;
  1265.                 
  1266.         h = thePixelShatter[i].h;
  1267.         v = thePixelShatter[i].v;
  1268.         if( h < minH )
  1269.             minH = h;
  1270.         if( h > maxH )
  1271.             maxH = h;
  1272.         if( v < minV )
  1273.             minV = v;
  1274.         if( v > maxV )
  1275.             maxV = v;
  1276.             
  1277.         h >>= 4;
  1278.         v >>= 4;
  1279.         
  1280.         offset = rowBytes * v;
  1281.         offset += h;
  1282.         
  1283.         addr += offset;
  1284.         
  1285.         *addr = thePixelShatter[i].color;
  1286.     }
  1287.     
  1288.     SetRect( &theRect, minH, minV, maxH, maxV );
  1289.     #ifdef USE_INVALID_RECTS
  1290.     DSpContext_InvalBackBufferRect( gTheContext, &theRect );
  1291.     #endif
  1292.     
  1293. }
  1294.  
  1295. //--------------------------------------------------------------  DrawLava
  1296. void DrawLava(void);
  1297. #if 0
  1298. void DrawLava(void)
  1299. {
  1300.     short where = RandomInt(640);
  1301.     short velocity = -(RandomInt(15) + 15);
  1302.  
  1303.     StartPixelShatter(    where, 460, 0, velocity, kShatterLavaBubble);
  1304. }
  1305. #endif
  1306.  
  1307. void DrawScoreFloaters(void);
  1308. void DrawScoreFloaters(void)
  1309. {
  1310. #if 0
  1311.     int i,j,count;
  1312.     Rect r;
  1313.     CGrafPtr theGrafPtr = workSrcMap;
  1314.     PixMap *theMap = *(theGrafPtr->portPixMap);
  1315.     short rowBytes = theMap->rowBytes & 0x3fff;
  1316.     char *addr = theMap->baseAddr;
  1317.     
  1318.     for(count = 0; count < numScoreFloater; count++)
  1319.     {
  1320.         r.top = theScoreFloater[count].location.v;
  1321.         r.left = theScoreFloater[count].location.h;
  1322.         r.bottom = theScoreFloater[count].location.v + 20;
  1323.         r.right = theScoreFloater[count].location.h + 60;
  1324.     
  1325.         addr = theMap->baseAddr + (r.top * rowBytes);
  1326.         
  1327.         for(j = r.top; j < r.bottom; j++)
  1328.         {
  1329.             for(i = r.left; i < r.right; i++)
  1330.             {
  1331.                 addr[i] = 0;
  1332.             }
  1333.             
  1334.             addr += rowBytes;
  1335.         }
  1336.     }
  1337. #else
  1338.     int count;
  1339.     Rect baseRect = {0,0,8,11};
  1340.         
  1341.     for(count = 0; count < numScoreFloater; count++)
  1342.     {
  1343.         short        digit;
  1344.         short        workNumber;
  1345.         Rect r = baseRect;
  1346.                 
  1347.         r.top += theScoreFloater[count].location.v;
  1348.         r.bottom += theScoreFloater[count].location.v;
  1349.         r.left += theScoreFloater[count].location.h;
  1350.         r.right += theScoreFloater[count].location.h;
  1351.         workNumber = theScoreFloater[count].score;
  1352.             
  1353.         digit = (workNumber + 1) / 1000;        // Do 1000's digit.
  1354.         digit = digit % 10L;
  1355.         if (digit != 0)
  1356.         {
  1357.             CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  1358.                     &((GrafPtr)workSrcMap)->portBits, 
  1359.                     &numbersSrc[digit], &r, srcCopy, 0L);
  1360.             #ifdef USE_INVALID_RECTS
  1361.             DSpContext_InvalBackBufferRect( gTheContext, &r );
  1362.             #endif
  1363.         }
  1364.         
  1365.         r.left += 11;
  1366.         r.right += 11;
  1367.  
  1368.         digit = (workNumber + 1) / 100;        // Do 100's digit.
  1369.         digit = digit % 10L;
  1370.         if ((digit != 0) || (workNumber >= 1000))
  1371.         {
  1372.             CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  1373.                     &((GrafPtr)workSrcMap)->portBits, 
  1374.                     &numbersSrc[digit], &r, srcCopy, 0L);
  1375.             #ifdef USE_INVALID_RECTS
  1376.             DSpContext_InvalBackBufferRect( gTheContext, &r );
  1377.             #endif
  1378.         }
  1379.  
  1380.         r.left += 11;
  1381.         r.right += 11;
  1382.                 
  1383.         digit = (workNumber + 1) / 10;            // Do 10's digit.
  1384.         digit = digit % 10L;
  1385.         if ((digit != 0) || (workNumber >= 100))
  1386.         {
  1387.             CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  1388.                     &((GrafPtr)workSrcMap)->portBits, 
  1389.                     &numbersSrc[digit], &r, srcCopy, 0L);
  1390.             #ifdef USE_INVALID_RECTS
  1391.             DSpContext_InvalBackBufferRect( gTheContext, &r );
  1392.             #endif
  1393.         }
  1394.         
  1395.         r.left += 11;
  1396.         r.right += 11;
  1397.  
  1398.         digit = (workNumber) % 10;            // Do 1's digit.
  1399.         CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  1400.                 &((GrafPtr)workSrcMap)->portBits, 
  1401.                 &numbersSrc[digit], &r, srcCopy, 0L);
  1402.         #ifdef USE_INVALID_RECTS
  1403.         DSpContext_InvalBackBufferRect( gTheContext, &r );
  1404.         #endif
  1405.     }
  1406. #endif
  1407. }
  1408.  
  1409. //--------------------------------------------------------------  DrawFrame
  1410.  
  1411. // This function is the "master" drawing function that calls all the above…
  1412. // routines.  It is called once per frame.
  1413.  
  1414. void DrawFrame (void)
  1415. {
  1416.     Boolean bannerInFront = false;
  1417.     
  1418.     {
  1419.         KeyMap theKeys;
  1420.         GetKeys(theKeys);
  1421.     
  1422.         if ((theKeys[1] & 0x004))
  1423.         {
  1424.             bannerInFront = true;
  1425.         }
  1426.     }
  1427.  
  1428.     if (!bannerInFront)
  1429.     {
  1430.         DrawBanner();
  1431.     }
  1432.  
  1433.     DrawTorches();                // Gee, draws the torches?
  1434.     
  1435.     DrawScoreFloaters();
  1436.     
  1437.     DrawHand();                    // Draws the hand?
  1438.     DrawEye();                    // A clue to easing your documentation demands…
  1439.     DrawPlayer();                // is to use "smart" names for your functions.
  1440.     CheckPlayerWrapAround();    // Check for player wrap-around.
  1441.     DrawEnemies();                // Handle all sphinx-type enemy drawing.
  1442.  
  1443.     DrawObelisks();            // draw the obelisks
  1444.     DrawPixelShatter();            // draw exploding pixels
  1445.     
  1446.     DrawLava();                    // add sparkling lava
  1447.  
  1448.     if (bannerInFront)
  1449.     {
  1450.         DrawBanner();
  1451.     }    
  1452.  
  1453. }
  1454.  
  1455. //--------------------------------------------------------------  GameQuitGraphics
  1456.  
  1457. void GameQuitGraphics(void)
  1458. {
  1459.     short h,v;
  1460.     
  1461.     for(v = 0; v < 480; v += 24)
  1462.     {
  1463.         for(h = 0; h < 640; h += 32)
  1464.         {
  1465.                 StartPixelShatter(h, v, 0, 0, kShatterLightningDust);
  1466.         }
  1467.     }
  1468.  
  1469.     CopyBits(    &((GrafPtr)origBackSrcMap)->portBits, 
  1470.                 &((GrafPtr)backSrcMap)->portBits, 
  1471.                 &backSrcRect, &backSrcRect, srcCopy, 0L);
  1472.     #ifdef USE_INVALID_RECTS
  1473.     DSpContext_InvalBackBufferRect( gTheContext, &backSrcRect );
  1474.     #endif
  1475. }
  1476.  
  1477. //--------------------------------------------------------------  GameIdleAnimation
  1478.  
  1479. void GameIdleAnimation(void)
  1480. {
  1481.     // do our idle animation
  1482.     DSpContext_GetBackBuffer( gTheContext, kDSpBufferKind_Normal, &workSrcMap );
  1483.     DumpBackToWorkMap();                    // clear the screen
  1484.     DrawBanner();
  1485.     DrawTorches();
  1486.     HandlePixelShatter();
  1487.     HandleLava();
  1488.     DrawLava();
  1489.     
  1490.     if (helpOpen)
  1491.     {
  1492.         CopyBits(&((GrafPtr)helpSrcMap)->portBits, 
  1493.             &((GrafPtr)workSrcMap)->portBits, 
  1494.             &helpSrc, &helpDest, srcCopy, 0L);
  1495.         #ifdef USE_INVALID_RECTS
  1496.         DSpContext_InvalBackBufferRect( gTheContext, &helpDest );
  1497.         #endif
  1498.     }
  1499.     
  1500.     DrawPixelShatter();
  1501.     HandleLightning();
  1502.  
  1503.     DSpContext_SwapBuffers( gTheContext, NULL, NULL );    
  1504. }
  1505.  
  1506.